package com.easylinkin.linkappapi.grid.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.grid.entity.GridSecurityCheckItem;
import com.easylinkin.linkappapi.grid.entity.GridSecurityLog;
import com.easylinkin.linkappapi.grid.entity.GridSecurityLogRelation;
import com.easylinkin.linkappapi.grid.mapper.GridSecurityCheckItemMapper;
import com.easylinkin.linkappapi.grid.mapper.GridSecurityLogMapper;
import com.easylinkin.linkappapi.grid.mapper.GridSecurityLogRelationMapper;
import com.easylinkin.linkappapi.grid.models.dto.GridSecurityCheckItemDTO;
import com.easylinkin.linkappapi.grid.models.dto.GridSecurityLogDayDTO;
import com.easylinkin.linkappapi.grid.models.dto.GridSecurityLogExportDTO;
import com.easylinkin.linkappapi.grid.models.handler.GridSecurityLogExcelHandler;
import com.easylinkin.linkappapi.grid.models.handler.GridSecurityLogMultiSheetHandler;
import com.easylinkin.linkappapi.grid.models.query.GridSecurityLogQuery;
import com.easylinkin.linkappapi.grid.service.IGridSecurityLogService;
import com.easylinkin.linkappapi.penetsecuremanage.entity.RailLinkappGridManagementInfo;
import com.easylinkin.linkappapi.penetsecuremanage.mapper.RailLinkappGridManagementInfoMapper;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.tenant.entity.LinkappTenant;
import com.easylinkin.linkappapi.tenant.mapper.LinkappTenantMapper;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 网格安全员日志 服务实现类
 *
 * @author xy
 * @since 2025-06-30
 */
@Service
public class GridSecurityLogServiceImpl extends ServiceImpl<GridSecurityLogMapper, GridSecurityLog> implements IGridSecurityLogService {

    @Autowired
    private LinkappUserContextProducer linkappUserContextProducer;

    @Autowired
    private GridSecurityLogRelationMapper gridSecurityLogRelationMapper;

    @Autowired
    private GridSecurityCheckItemMapper gridSecurityCheckItemMapper;

    @Autowired
    private RailLinkappGridManagementInfoMapper gridManagementInfoMapper;

    @Autowired
    private LinkappTenantMapper linkappTenantMapper;

    @Override
    public IPage<GridSecurityLog> queryPage(RequestModel<GridSecurityLogQuery> requestModel) {
        requestModel.getCustomQueryParams().setTenantId(linkappUserContextProducer.getTenantId());
        return baseMapper.queryPage(requestModel.getPage(), requestModel.getCustomQueryParams());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdateLog(GridSecurityLog gridSecurityLog) {
        checkExist(gridSecurityLog);
        setBase(gridSecurityLog);
        if (ObjectUtil.isNotEmpty(gridSecurityLog.getId())) {
            this.updateById(gridSecurityLog);
        } else {
            this.save(gridSecurityLog);
        }
        List<GridSecurityCheckItemDTO> checkItems = gridSecurityLog.getCheckItems();
        for (GridSecurityCheckItemDTO gridSecurityCheckItemDTO : checkItems) {
            if (ObjectUtil.isNotEmpty(gridSecurityCheckItemDTO.getCheckChildItems())) {
                for (GridSecurityCheckItem item : gridSecurityCheckItemDTO.getCheckChildItems()) {
                    GridSecurityLogRelation gridSecurityLogRelation = item.getGridSecurityLogRelation();
                    setBaseRelation(gridSecurityLogRelation);
                    if (ObjectUtil.isNotEmpty(gridSecurityLogRelation.getId())) {
                        gridSecurityLogRelationMapper.updateById(gridSecurityLogRelation);
                    } else {
                        gridSecurityLogRelation.setLogId(gridSecurityLog.getId());
                        gridSecurityLogRelation.setCheckItemId(item.getId());
                        gridSecurityLogRelationMapper.insert(gridSecurityLogRelation);
                    }
                }
            }
        }
    }

    private void checkExist(GridSecurityLog gridSecurityLog) {
        String tenantId = linkappUserContextProducer.getTenantId();
        // 校验检查项是否为空
        if (ObjectUtil.isEmpty(gridSecurityLog.getCheckItems())) {
            throw new BusinessException("检查项不能为空");
        }
        // 校验同一天只有一条记录
        LambdaQueryWrapper<GridSecurityLog> eq = new LambdaQueryWrapper<GridSecurityLog>()
                .eq(GridSecurityLog::getTenantId, tenantId)
                .eq(GridSecurityLog::getGridId, gridSecurityLog.getGridId())
                .eq(GridSecurityLog::getLogTime, gridSecurityLog.getLogTime());
        if (ObjectUtil.isNotEmpty(gridSecurityLog.getId())) {
            eq.ne(GridSecurityLog::getId, gridSecurityLog.getId());
        }
        int count = this.count(eq);
        if (count > 0) {
            throw new BusinessException("同一天只能有一条记录");
        }
    }

    @Override
    public boolean checkGridLog(Long gridId, String logTime) {
        String tenantId = linkappUserContextProducer.getTenantId();
        LambdaQueryWrapper<GridSecurityLog> eq = new LambdaQueryWrapper<GridSecurityLog>()
               .eq(GridSecurityLog::getTenantId, tenantId)
               .eq(GridSecurityLog::getGridId, gridId)
               .eq(GridSecurityLog::getLogTime, logTime);
        int count = this.count(eq);
        if (count > 0) {
            return true;
        }
        return false;
    }

    private void setBase(GridSecurityLog gridSecurityLog) {
        String tenantId = linkappUserContextProducer.getTenantId();
        gridSecurityLog.setTenantId(tenantId);
        gridSecurityLog.setModifyTime(new Date());
        gridSecurityLog.setModifyId(linkappUserContextProducer.getCurrent().getId());
        //没有id就是新增,有就是编辑
        if (ObjectUtil.isEmpty(gridSecurityLog.getId())) {
            gridSecurityLog.setCreateId(linkappUserContextProducer.getCurrent().getId());
            gridSecurityLog.setCreateTime(new Date());
            gridSecurityLog.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        }
    }

    private void setBaseRelation(GridSecurityLogRelation gridSecurityLogRelation) {
        gridSecurityLogRelation.setModifyTime(new Date());
        gridSecurityLogRelation.setModifyId(linkappUserContextProducer.getCurrent().getId());
        //没有id就是新增,有就是编辑
        if (ObjectUtil.isEmpty(gridSecurityLogRelation.getId())) {
            gridSecurityLogRelation.setCreateId(linkappUserContextProducer.getCurrent().getId());
            gridSecurityLogRelation.setCreateTime(new Date());
        }
    }

    @Override
    public List<GridSecurityCheckItemDTO> queryAllCheckItems() {
        List<GridSecurityCheckItemDTO> gridSecurityCheckItemDTOS = gridSecurityCheckItemMapper.queryAllCheckItems();
        for (GridSecurityCheckItemDTO gridSecurityCheckItemDTO : gridSecurityCheckItemDTOS) {
            List<GridSecurityCheckItem> checkItems = gridSecurityCheckItemDTO.getCheckChildItems();
            for (GridSecurityCheckItem item : checkItems) {
                item.setGridSecurityLogRelation(new GridSecurityLogRelation());
            }
        }
        return gridSecurityCheckItemDTOS;
    }

    @Override
    public GridSecurityLog queryById(Long id) {
        GridSecurityLog gridSecurityLog = baseMapper.queryById(id);
        if (ObjectUtil.isNotEmpty(gridSecurityLog)) {
            List<GridSecurityLogRelation> relationList = gridSecurityLogRelationMapper.selectList(new LambdaQueryWrapper<GridSecurityLogRelation>()
                   .eq(GridSecurityLogRelation::getLogId, id));
            Map<Long, GridSecurityLogRelation> relationMap = relationList.stream().collect(Collectors.toMap(GridSecurityLogRelation::getCheckItemId, p -> p));
            List<GridSecurityCheckItemDTO> gridSecurityCheckItemDTOS = gridSecurityCheckItemMapper.queryAllCheckItems();
            for (GridSecurityCheckItemDTO gridSecurityCheckItemDTO : gridSecurityCheckItemDTOS) {
                List<GridSecurityCheckItem> checkItems = gridSecurityCheckItemDTO.getCheckChildItems();
                for (GridSecurityCheckItem item : checkItems) {
                    GridSecurityLogRelation gridSecurityLogRelation = relationMap.get(item.getId());
                    if (ObjectUtil.isEmpty(gridSecurityLogRelation)) {
                        gridSecurityLogRelation = new GridSecurityLogRelation();
                    }
                    item.setGridSecurityLogRelation(gridSecurityLogRelation);
                }
            }
            gridSecurityLog.setCheckItems(gridSecurityCheckItemDTOS);
        }
        return gridSecurityLog;
    }

    @Override
    public List<GridSecurityLogDayDTO> queryByMonth(String month) {
        // 按月份查询所有日期
        if (StringUtils.isEmpty(month)) {
          throw new BusinessException("月份不能为空");
        }
        DateTime dateTime = DateUtil.parse(month, "yyyy-MM");
        Date start = DateUtil.beginOfMonth(dateTime);
        Date end = DateUtil.endOfMonth(dateTime);
        List<DateTime> dayList = DateUtil.rangeToList(start, end, DateField.DAY_OF_MONTH);
        // 1.查询所有网格点
        String tenantId = linkappUserContextProducer.getTenantId();
        List<RailLinkappGridManagementInfo> gridIdList = gridManagementInfoMapper.queryByTenantId(tenantId);
        if (ObjectUtil.isEmpty(gridIdList)) {
            return null;
        }
        List<Long> gridIdListLong = gridIdList.stream().map(RailLinkappGridManagementInfo::getId).collect(Collectors.toList());
        // 2.查询所有日志
        LambdaQueryWrapper<GridSecurityLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(GridSecurityLog::getTenantId, tenantId);
        queryWrapper.between(GridSecurityLog::getLogTime, start, end);
        queryWrapper.in(GridSecurityLog::getGridId, gridIdListLong);
        List<GridSecurityLog> gridSecurityLogs = baseMapper.selectList(queryWrapper);
        Map<Date, List<GridSecurityLog>> logMap = gridSecurityLogs.stream().collect(Collectors.groupingBy(GridSecurityLog::getLogTime));
        List<GridSecurityLogDayDTO> result = new ArrayList<>();
        // 2.1 查询默认检查项
        List<GridSecurityCheckItemDTO> checkItems = this.queryAllCheckItems();
        // 3.按日期分组
        if (ObjectUtil.isNotEmpty(dayList)) {
            for (DateTime date : dayList) {
                List<GridSecurityLog> gridSecurityLogList = logMap.get(date);
                GridSecurityLogDayDTO gridSecurityLogDayDTO = setBaseDay(date, gridSecurityLogList, gridIdList, checkItems);
                result.add(gridSecurityLogDayDTO);
            }
        }
        return result;
    }

    private GridSecurityLogDayDTO setBaseDay(Date date, List<GridSecurityLog> gridSecurityLogList, List<RailLinkappGridManagementInfo> gridIdList, List<GridSecurityCheckItemDTO> checkItems) {
        Map<Long, GridSecurityLog> logMap = null;
        if (ObjectUtil.isNotEmpty(gridSecurityLogList)) {
            logMap = gridSecurityLogList.stream().collect(Collectors.toMap(GridSecurityLog::getGridId, p -> p));
        }
        GridSecurityLogDayDTO gridSecurityLogDayDTO = new GridSecurityLogDayDTO();
        gridSecurityLogDayDTO.setDay(DateUtil.dayOfMonth(date));
        gridSecurityLogDayDTO.setDate(DateUtil.format(date, "yyyy-MM-dd"));
        List<GridSecurityLog> logList = new ArrayList<>();
        Integer finishCount = 0;
        Integer finishStatus = 0;
        for (RailLinkappGridManagementInfo managementInfo : gridIdList) {
            GridSecurityLog gridSecurityLog = null;
            if (logMap != null) {
                gridSecurityLog = logMap.get(managementInfo.getId());
            }
            GridSecurityLog gridSecurityLogDetail;
            if (ObjectUtil.isNotEmpty(gridSecurityLog)) {
                finishCount++;
                gridSecurityLogDetail = this.queryById(gridSecurityLog.getId());
                gridSecurityLogDetail.setFinishedFlag(true);
            } else {
                gridSecurityLogDetail = new GridSecurityLog();
                gridSecurityLogDetail.setGridId(managementInfo.getId());
                gridSecurityLogDetail.setGridName(managementInfo.getGridName());
                gridSecurityLogDetail.setCheckItems(checkItems);
                gridSecurityLogDetail.setFinishedFlag(false);
            }
            logList.add(gridSecurityLogDetail);
        }
        // 完成状态 0-未完成 1-已完成 2-部分完成
        finishStatus = finishCount == gridIdList.size() ? 1 : (finishCount > 0 ? 2 : 0);
        gridSecurityLogDayDTO.setFinishStatus(finishStatus);
        gridSecurityLogDayDTO.setGridSecurityLogList(logList);
        return gridSecurityLogDayDTO;
    }

    @Override
    public void exportByMonth(String month, HttpServletResponse response) throws IOException {
        String tenantId = linkappUserContextProducer.getTenantId();
        LinkappTenant tenant = linkappTenantMapper.getById(tenantId);
        String projectName = tenant.getPlatformProjectName();

        List<GridSecurityLogDayDTO> logs = this.queryByMonth(month);

        if (ObjectUtil.isEmpty(logs)) {
            throw new BusinessException("暂无数据");
        }

        // 创建临时目录
        String tempDir = System.getProperty("java.io.tmpdir") + "grid_logs_" + System.currentTimeMillis() + "/";
        new File(tempDir).mkdirs();

        // 按网格分组日志
        Map<String, List<GridSecurityLog>> gridLogsMap = new HashMap<>();
        for (GridSecurityLogDayDTO dayLog : logs) {
            for (GridSecurityLog log : dayLog.getGridSecurityLogList()) {
                gridLogsMap.computeIfAbsent(log.getGridName(), k -> new ArrayList<>()).add(log);
            }
        }

        // 为每个网格生成文件
        for (Map.Entry<String, List<GridSecurityLog>> entry : gridLogsMap.entrySet()) {
            String gridName = entry.getKey();
            List<GridSecurityLog> gridLogs = entry.getValue();
            // 判断网格gridLogs 是否生成
            gridLogs = gridLogs.stream().filter(log -> log.getId() != null).collect(Collectors.toList());
            if (ObjectUtil.isEmpty(gridLogs)) {
                continue;
            }

            String fileName = projectName + gridName + month + "网格安全员日志台账.xlsx";
            String filePath = tempDir + fileName;

            // 生成Excel文件 (需要实现Excel导出逻辑)
            exportLogsToExcel(gridLogs, filePath);
        }

        // 压缩所有文件
        String zipFileName = projectName + month + "网格安全员日志台账_" + DateUtil.format(new Date(), "yyyyMMdd") + ".zip";
        String zipFilePath = tempDir + "../" + zipFileName;

        try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFilePath))) {
            File[] files = new File(tempDir).listFiles();
            if (files != null) {
                for (File file : files) {
                    try (FileInputStream fis = new FileInputStream(file)) {
                        ZipEntry zipEntry = new ZipEntry(file.getName());
                        zipOut.putNextEntry(zipEntry);
                        byte[] bytes = new byte[1024];
                        int length;
                        while ((length = fis.read(bytes)) >= 0) {
                            zipOut.write(bytes, 0, length);
                        }
                    }
                }
            }
        }

        // 设置响应头
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(zipFileName, "UTF-8"));

        // 传输文件
        try (FileInputStream fis = new FileInputStream(zipFilePath);
             OutputStream os = response.getOutputStream()) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
        }

        // 删除临时文件
        FileUtils.deleteDirectory(new File(tempDir));
        new File(zipFilePath).delete();
    }

    private void exportLogsToExcel(List<GridSecurityLog> logs, String filePath) {
        try {
            // 过滤有效的日志记录
            List<GridSecurityLog> validLogs = logs.stream()
                    .filter(log -> log.getId() != null)
                    .collect(Collectors.toList());
            
            if (ObjectUtil.isEmpty(validLogs)) {
                return;
            }

            // 按日期分组日志（过滤掉logTime为空的记录）
            Map<Date, List<GridSecurityLog>> dateLogsMap = validLogs.stream()
                    .filter(log -> log.getLogTime() != null)
                    .collect(Collectors.groupingBy(GridSecurityLog::getLogTime, LinkedHashMap::new, Collectors.toList()));
            
            if (dateLogsMap.isEmpty()) {
                return; // 没有有效的日期数据
            }
            
            // 获取网格名称
            String gridName = validLogs.get(0).getGridName();
            
            // 准备每个日期的数据
            Map<String, GridSecurityLogMultiSheetHandler.DaySheetData> dayDataMap = new LinkedHashMap<>();
            
            // 按日期排序处理
            List<Date> sortedDates = new ArrayList<>(dateLogsMap.keySet());
            sortedDates.sort(Date::compareTo);
            
            for (Date logDate : sortedDates) {
                List<GridSecurityLog> dayLogs = dateLogsMap.get(logDate);
                
                // 获取当天的第几天作为sheet名
                int dayOfMonth = DateUtil.dayOfMonth(logDate);
                String sheetName = String.valueOf(dayOfMonth);
                
                // 准备该日期的导出数据
                List<GridSecurityLogExportDTO> dayExportData = new ArrayList<>();
                int serialNumber = 0;
                
                // 获取检查时间和检查人员（取第一条记录的信息）
                GridSecurityLog firstDayLog = dayLogs.get(0);
                String checkTime = firstDayLog.getLogTime() != null ? DateUtil.format(firstDayLog.getLogTime(), "yyyy-MM-dd HH:mm") : "";
                String checker = firstDayLog.getUserName() != null ? firstDayLog.getUserName() : "";
                
                for (GridSecurityLog log : dayLogs) {
                    if (log.getCheckItems() != null) {
                        for (GridSecurityCheckItemDTO checkItemDTO : log.getCheckItems()) {
                            if (checkItemDTO.getCheckChildItems() != null) {
                                for (GridSecurityCheckItem item : checkItemDTO.getCheckChildItems()) {
                                    serialNumber++;
                                    GridSecurityLogRelation relation = item.getGridSecurityLogRelation();
                                    if (relation == null) {
                                        relation = new GridSecurityLogRelation();
                                    }

                                    GridSecurityLogExportDTO exportDTO = new GridSecurityLogExportDTO();
                                    exportDTO.setSerialNumber(serialNumber);
                                    exportDTO.setCheckItem(checkItemDTO.getName());
                                    exportDTO.setCheckContent(item.getName());
                                    exportDTO.setCheckStatus(isEmptyOrNull(relation.getCheckDesc()) ? "无" : relation.getCheckDesc());
                                    exportDTO.setProblems(isEmptyOrNull(relation.getProblemDesc()) ? "无" : relation.getProblemDesc());
                                    exportDTO.setRectification(isEmptyOrNull(relation.getImproveDesc()) ? "无" : relation.getImproveDesc());
                                    exportDTO.setRemark(relation.getRemark() != null ? relation.getRemark() : "");
                                    exportDTO.setGridName(log.getGridName());
                                    exportDTO.setCheckDate(log.getLogTime() != null ? DateUtil.format(log.getLogTime(), "yyyy-MM-dd") : "");
                                    exportDTO.setChecker(log.getUserName() != null ? log.getUserName() : "");
                                    
                                    dayExportData.add(exportDTO);
                                }
                            }
                        }
                    }
                }
                
                // 创建DaySheetData
                GridSecurityLogMultiSheetHandler.DaySheetData daySheetData = 
                    new GridSecurityLogMultiSheetHandler.DaySheetData(checkTime, checker, dayExportData, dayOfMonth);
                dayDataMap.put(sheetName, daySheetData);
            }
            
            // 使用多sheet页处理器进行导出
            GridSecurityLogMultiSheetHandler multiSheetHandler = new GridSecurityLogMultiSheetHandler(gridName, dayDataMap);
            
            // 使用EasyExcel的ExcelWriter创建多个sheet页
            try (ExcelWriter excelWriter = EasyExcel.write(filePath).build()) {
                for (String sheetName : dayDataMap.keySet()) {
                    WriteSheet writeSheet = EasyExcel.writerSheet(sheetName)
                            .head((Class<?>) null)  // 不使用自动表头
                            .registerWriteHandler(multiSheetHandler)
                            .build();
                    
                    // 写入空数据，实际数据在处理器中写入
                    excelWriter.write(new ArrayList<>(), writeSheet);
                }
            }

        } catch (Exception e) {
            throw new RuntimeException("导出Excel失败", e);
        }
    }
    
    private boolean isEmptyOrNull(String value) {
        return value == null || value.trim().isEmpty();
    }
}